home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume2 / emake < prev    next >
Encoding:
Internet Message Format  |  1991-08-07  |  7.8 KB

  1. From: rsalz@pineapple.bbn.com
  2. Newsgroups: comp.sources.misc
  3. Subject: v02i044: emake - "pre-processor" for makefiles
  4. Message-ID: <7192@ncoast.UUCP>
  5. Date: 6 Feb 88 01:24:10 GMT
  6. Approved: allbery@ncoast.UUCP
  7.  
  8. Comp.sources.misc: Volume 2, Issue 44
  9. Submitted-By: "Rich $alz" <rsalz@pineapple.bbn.COM>
  10. Archive-Name: emake
  11.  
  12. [Cross-pollination?  ;-)  ++bsa]
  13.  
  14. One easy way to have standard make appear to be more powerful, is to use
  15. m4 or the C preprocessor so you can define parameterized macros for things
  16. like simple programs, and the like.  Our project used to do this, and I
  17. notice that the X software uses something called "imake" which does this
  18. too.
  19. We used to use shell scripts, then I wrote this.  (Then we rewrote all our
  20. Makefiles so we don't need this at all.)  It basically runs cpp over a
  21. file named Dmakefile to create something called MakeAuto, it then invokes
  22. make on that.  If MakeAuto is more recent then Dmakefile, you save the cpp
  23. overhead (this is the big problem with imake).  A -D option also forces a
  24. rebuild.
  25.  
  26. This lets you do cute things like put #ifdef's in your Makefile for
  27. different unices.  Nice.  It doesn't really handle multi-line #define's as
  28. the X imake does, but you could probably slip that in by putting in a
  29. filter pass to translate @@ into \n.
  30.  
  31. Known to work on BSD derivatives, should take five or so minutes to port
  32. to others (e.g., no sys/file.h, or using cc -E instead of /lib/cpp.)
  33.  
  34. Hope others find it useful.
  35.     /r$
  36.  
  37. #! /bin/sh
  38. # This is a shell archive.  Remove anything before this line, then unpack
  39. # it by saving it into a file and typing "sh file".  To overwrite existing
  40. # files, type "sh file -c".  You can also feed this as standard input via
  41. # unshar, or by typing "sh <file", e.g
  42. PATH=/bin:/usr/bin: ; export PATH
  43. if test -f 'emake.c' -a "${1}" != "-c" ; then 
  44.   echo shar: Will not clobber existing file \"'emake.c'\"
  45. else
  46. echo shar: Extracting \"'emake.c'\" \(5585 characters\)
  47. sed "s/^X//" >'emake.c' <<'END_OF_FILE'
  48. X/*
  49. X**  EMAKE
  50. X**  Run /lib/cpp over Dmakefile (if necessary), then call make.
  51. X**  There is a prolog file, the Dmakefile, and the epilog file;
  52. X**  see the List variable to set these.
  53. X**
  54. X**  This creates a makefile called MakeAuto, so you don't have to
  55. X**  spend all that silly time in cpp if the Dmakefile hasn't changed.
  56. X*/
  57. X#include <stdio.h>
  58. X#include <errno.h>
  59. X#include <sys/types.h>
  60. X#include <sys/stat.h>
  61. X#include <sys/file.h>
  62. X
  63. X#ifdef    WAIT_UNION
  64. X#include <sys/wait.h>
  65. X#define WAITVALUE(W)        ((W).w_retcode)
  66. Xtypedef union wait WAITER;
  67. X#else
  68. X#define WAITVALUE(W)        ((W) >> 8)
  69. Xtypedef int WAITER;
  70. X#endif    /* WAIT_UNION */
  71. X
  72. X
  73. X/*
  74. X**  Handy shorthands.
  75. X*/
  76. X#define STDOUT        1
  77. X#define STDERR        2
  78. X#define WHITE(c)    ((c) == ' ' || (c) == '\t')
  79. X#define WRITE(s)    (void)write(STDERR, s, sizeof s - 1);
  80. X
  81. X
  82. X/*
  83. X**  Datatype and variable to hold the list of CPP directives that we should
  84. X**  pass through (make's comment character is '#', which clashes).
  85. X*/
  86. Xtypedef struct {
  87. X    char    Value[8];
  88. X    int        Length;
  89. X} ALIST;
  90. X
  91. XALIST      Directives[] = {
  92. X    { "include", 7 },    { "define", 6 },    { "ifndef", 6 },
  93. X    { "ifdef", 5 },    { "undef", 5 },        { "endif", 5 },
  94. X    { "else", 4 },    { "line", 4 },        { "if", 2},
  95. X    { "", -1 }
  96. X};
  97. X
  98. X/* Other globals. */
  99. Xchar      TempInput[]  = "MakeIXXXXXX";    /* CPP input file        */
  100. Xchar      TempOutput[] = "MakeOXXXXXX";    /* CPP output file        */
  101. Xchar      DMAKEFILE[] = "Dmakefile";    /* Emake's makefile        */
  102. Xchar      MAKEFILE[] = "MakeAuto";    /* Generated makefile        */
  103. Xchar     *List[] = {            /* Sources for emake        */
  104. X    "/usr/cronus/clib/dmakedefs", DMAKEFILE, "/usr/cronus/clib/dtargets", NULL
  105. X};
  106. X
  107. X/* Linked in later. */
  108. Xextern int     errno;
  109. Xextern char    *mktemp();
  110. Xextern char    *malloc();
  111. X
  112. X
  113. X/*
  114. X**  Print error message, clean up, and die.
  115. X*/
  116. Xvoid
  117. XQuit(s)
  118. X    char    *s;
  119. X{
  120. X    perror(s);
  121. X#ifndef    DEBUG
  122. X    if ((unlink(TempInput) < 0 && errno != ENOENT)
  123. X     || (unlink(TempOutput) < 0 && errno != ENOENT))
  124. X    perror("Error in QUIT cleanup");
  125. X#endif    /* DEBUG */
  126. X    _exit(1);
  127. X}
  128. X
  129. X
  130. X/*
  131. X**  Pre-process the input files, building the make control file.
  132. X*/
  133. Xvoid
  134. XPrepare(Cargv)
  135. X    char        **Cargv;
  136. X{
  137. X    register ALIST     *D;
  138. X    register FILE     *F;
  139. X    register FILE     *In;
  140. X    register char     *p;
  141. X    register int      i;
  142. X    register int      j;
  143. X    WAITER          W;
  144. X    char        **Name;
  145. X    char          buff[BUFSIZ];
  146. X
  147. X    /* Create tempfile for CPP input. */
  148. X    if ((F = fopen(TempInput, "w")) == NULL)
  149. X    Quit(TempInput);
  150. X
  151. X    /* Write each input file to the temporary output. */
  152. X    for (Name = List; *Name; Name++) {
  153. X    if ((In = fopen(*Name, "r")) == NULL)
  154. X        Quit(*Name);
  155. X
  156. X    /* Read input, eliding #foo lines if foo is not a cpp directive. */
  157. X    while (fgets(buff, sizeof buff, In))
  158. X        if (buff[0] != '#')
  159. X        (void)fputs(buff, F);
  160. X        else {
  161. X        for (p = &buff[1]; *p && WHITE(*p); p++)
  162. X            p++;
  163. X        for (i = strlen(p), D = Directives; D->Length >= 0; D++)
  164. X            if (i > D->Length
  165. X             && strncmp(p, D->Value, D->Length) == 0
  166. X             && WHITE(p[D->Length])) {
  167. X            (void)fputs(buff, F);
  168. X            break;
  169. X            }
  170. X        }
  171. X
  172. X    (void)fclose(In);
  173. X    }
  174. X    (void)fclose(F);
  175. X
  176. X    /* Create a file to hold the cpp output. */
  177. X    i = open(TempOutput, O_WRONLY | O_TRUNC | O_CREAT, 0666);
  178. X
  179. X    /* Call the pre-processor. */
  180. X    if ((j =  fork()) == 0) {
  181. X    /* I tried to use dup() and dup2(), but they didn't work... */
  182. X    if (close(STDOUT) < 0 || dup(i) != STDOUT)
  183. X        perror("Error in CPP redirection");
  184. X    execv(Cargv[0], Cargv);
  185. X    perror(Cargv[0]);
  186. X    _exit(1);
  187. X    }
  188. X
  189. X    /* Wait for it. */
  190. X    while (wait(&W) != j)
  191. X    ;
  192. X    if (WAITVAL(W))
  193. X    Quit("CPP failure");
  194. X
  195. X    /* Copy cpp output to MAKEFILE, eliding all "#" lines. */
  196. X    (void)close(i);
  197. X    if ((In = fopen(TempOutput, "r")) == NULL
  198. X     || (F = fopen(MAKEFILE, "w")) == NULL)
  199. X    Quit("Scanning cpp output");
  200. X    (void)fputs("## HANDS OFF THIS FILE--IT WAS AUTOMATICALLY CREATED!!\n", F);
  201. X    while (fgets(buff, sizeof buff, In))
  202. X    if (buff[0] != '#')
  203. X        for (p = buff; *p && *p != '\n'; p++)
  204. X        if (!WHITE(*p)) {
  205. X            (void)fputs(buff, F);
  206. X            break;
  207. X        }
  208. X    (void)fclose(In);
  209. X    (void)fclose(F);
  210. X    if (unlink(TempInput) < 0 || unlink(TempOutput) < 0)
  211. X    perror("Error in cleaning up temp files");
  212. X}
  213. X
  214. X
  215. Xmain(ac, av)
  216. X    int              ac;
  217. X    register char     *av[];
  218. X{
  219. X    register char    **Margv;
  220. X    register char    **Cargv;
  221. X    register char     *p;
  222. X    register int      Mcount;
  223. X    register int      Ccount;
  224. X    register int      Force;
  225. X    struct stat          Sb1;
  226. X    struct stat          Sb2;
  227. X
  228. X    /* Is it all there? */
  229. X    if (stat(DMAKEFILE, &Sb1) < 0)
  230. X    Quit("Required file Dmakefile is missing");
  231. X
  232. X    /* Is Dmakefile newer than MakeFile? */
  233. X    Force = stat(MAKEFILE, &Sb2) < 0 || Sb1.st_mtime >= Sb2.st_mtime;
  234. X
  235. X    /* Build argument list stubs. */
  236. X    Margv = (char **)malloc((unsigned int)(ac + 4) * sizeof (char *));
  237. X    Margv[0] = "make";
  238. X    Margv[1] = "-f";
  239. X    Margv[2] = MAKEFILE;
  240. X    Cargv = (char **)malloc((unsigned int)(ac + 3) * sizeof (char *));
  241. X    Cargv[0] = "/lib/cpp";
  242. X    Cargv[1] = "-I/usr/cronus/include";
  243. X
  244. X    /* Create spool files. */
  245. X    (void)mktemp(TempInput);
  246. X    (void)mktemp(TempOutput);
  247. X
  248. X    /* Scan arg list, moving "-Dxxx" to cpp, all other stuff to make. */
  249. X    for (Mcount = 3, Ccount = 2; p = *++av; )
  250. X    if (p[0] == '-' && p[1] == 'D') {
  251. X        Force++;
  252. X        Cargv[Ccount++] = p;
  253. X    }
  254. X    else
  255. X        Margv[Mcount++] = p;
  256. X    Cargv[Ccount++] = TempInput;
  257. X    Cargv[Ccount] = NULL;
  258. X    Margv[Mcount] = NULL;
  259. X
  260. X    /* Rebuild MAKEFILE if necessary. */
  261. X    if (Force) {
  262. X    static char    REBUILD[] = "Rebuilding...";
  263. X    static char    DONE[] = "  done\n";
  264. X
  265. X    WRITE(REBUILD);
  266. X    Prepare(Cargv);
  267. X    WRITE(DONE);
  268. X    }
  269. X
  270. X    /* Now have make do the real work. */
  271. X    (void)execvp(Margv[0], Margv);
  272. X    Quit(Margv[0]);
  273. X}
  274. END_OF_FILE
  275. if test 5585 -ne `wc -c <'emake.c'`; then
  276.     echo shar: \"'emake.c'\" unpacked with wrong size!
  277. fi
  278. # end of 'emake.c'
  279. fi
  280. echo shar: End of shell archive.
  281. exit 0
  282.